#include "Analyze.h"
#include "UpfModel.h"
#include <iterator>
using namespace std;

// smc
string detect_warning(PwSupplyNet* ground)
{
    string ststr = "";
    for (auto st : ground->getPststates()){
        if(st->getValue() != 0){
            ststr += "\"";
            ststr += st->getName();
            ststr += "\" ";
        }
    }
    PwSupplyPort* driver = ground->getDriver()->getSupplyPort();
    for (auto st : driver->getPststates()){
        if(st->getValue() != 0){
            ststr += "\"";
            ststr += st->getName();
            ststr += "\" ";
        }
    }
    return ststr;
}

void PwSupplyNet::printError()
{
    PwSupplyConn* conn = this->getDriver();
    if (conn) {
        PwSupplyPort* sp = conn->getSupplyPort();
        set<PwSupplyState*> states_defined(sp->beginStates(), sp->endStates());
        set<PwSupplyState*> temp = this->getPststates();
        set<PwSupplyState*> states_unused;
        set_difference( states_defined.begin(), states_defined.end(),
                temp.begin(), temp.end(),
                inserter( states_unused, states_unused.begin() ) );
        for(auto stn : states_unused){
            cout<<"State \""<<stn->getName()<<"\" defined for \""<<this->getHierName()<<"\" is unused in PST!"<<endl;
        }
    }
}

void PwSupplyPort::printError()
{
    set<PwSupplyState*> states_defined(this->beginStates(), this->endStates());
    set<PwSupplyState*> temp = this->getPststates();
    set<PwSupplyState*> states_unused;
    set_difference( states_defined.begin(), states_defined.end(),
            temp.begin(), temp.end(),
            inserter( states_unused, states_unused.begin() ) );
    for(auto stn : states_unused){
        cout<<"State \""<<stn->getName()<<"\" defined for \""<<this->getHierName()<<"\" is unused in PST!"<<endl;
    }
}

PwSupplyState* PwSupplyNet::addPststate(std::string supplyState)
{
    PwSupplyState* pss = nullptr;
    PwSupplyConn* conn = this->getDriver();
    if (conn) {
        PwSupplyPort* sp = conn->getSupplyPort();
        pss = sp->findSupplyState(supplyState);
    }
    return pss;
}

PwSupplyState* PwSupplyPort::addPststate(std::string supplyState)
{
    PwSupplyState* pss = nullptr;
    pss = this->findSupplyState(supplyState);
    getPststates().insert(pss);
    return pss;
}

void PwScope::printError()
{
    for (pst_iter pst = beginPsts(); pst != endPsts(); ++pst)
    {
        for (vector<PwSupplyNetwork*>::iterator header = (*pst)->beginHeaders();
            header != (*pst)->endHeaders(); ++header)
        {
            (*header)->printError();
        }
    }
}

void PwObjMgr::printError()
{
    m_topScope->printError();
}

// Qin
void PwObjMgr::printSource(){
    if(m_topScope){
        m_topScope->findSource();
    }
    for (auto sp : sourcePorts){
        std::cout<<"Supply_Source "<<sp->getHierName()<<std::endl;
        sp->searchConn();
        std::cout<<"Supply_Net ";
        for (auto dn : driveNets)
            std::cout<<dn->getHierName()<<' ';
        std::cout<<std::endl<<"Supply_Port ";
        for (auto dp : drivePorts)
            std::cout<<dp->getHierName()<<' ';
        driveNets.clear();
        drivePorts.clear();  
        std::cout<<std::endl;
    }
    for (auto sn : sourceNets){
        std::cout<<"Supply_Source "<<sn->getHierName()<<std::endl;
        std::cout<<"Supply_Net ";
        sn->searchReceiver();
        for (auto dn : driveNets)
            std::cout<<dn->getHierName()<<' ';
        std::cout<<std::endl<<"Supply_Port ";
        for (auto dp : drivePorts)
            std::cout<<dp->getHierName()<<' ';
        driveNets.clear();
        drivePorts.clear();
        std::cout<<std::endl;
    }
}

void PwScope::findSource(){
    for (auto sp : m_sps){
        if((!sp->getHiConn())&&sp->isInput())
            sourcePorts.push_back(sp);
        if((!sp->getLoConn())&&sp->isOutput())
            sourcePorts.push_back(sp);        
    }

    for (auto sn : m_sns){
        if(!(sn->getDriver()))
            sourceNets.push_back(sn);
    }

    for (auto child : m_childs){
        child->findSource();
    }
}

inline void PwSupplyPort::searchConn(){
    drivePorts.push_back(this);
    if(m_loConn&&this->isInput()){
        m_loConn->searchNet();
    }
    if(m_hiConn&&this->isOutput()){
        m_hiConn->searchNet();
    }
}

inline void PwSupplyNet::searchReceiver(){
    driveNets.push_back(this);
    if(m_receivers.size()!=0)
		for (auto receiver : m_receivers){
			receiver->searchPort();
        }
}

inline void PwSupplyNet::searchDriver(){
    m_driver->searchPort();
}

inline void PwSupplyConn::searchNet(){
    m_supplyNet->searchReceiver();
}

inline void PwSupplyConn::searchPort(){
    m_supplyPort->searchConn();
}